using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.EventSystems;

namespace TripleMatch
{
    /// <summary>
    /// 单关关卡生成器
    /// </summary>
    public class LevelGenerator : MonoBehaviour
    {
        public class LevelGenerateData
        {
            public StandardDifficulty standardDifficulty;   //关卡标准难度
            public LevelConfigData standardDifficultyData;    //关卡标准难度对应的关卡数据 方块总数/总层数/样式种类
            public ShapeType shapeType;                     //单层形状样式
            public GradientType gradientType;               //整体渐变规则
            public int offset;                              //单层偏移范围
            public int extraDifficulty;                     //额外调整难度
        }

        [SerializeField] Transform m_recycleLayerTrans;

        /// <summary>
        /// 关卡初始化时使用的关卡配置数据
        /// </summary>
        private LevelGenerateData m_levelGenerateData;
        /// <summary>
        /// 关卡初始化时使用的关卡难度配置数据
        /// </summary>
        private LevelConfigData m_difficultData;
        /// <summary>
        /// 实际由于难度调节产生的额外的关卡数据
        /// </summary>
        private LevelConfigData m_extraDifficultData;
        /// <summary>
        /// 实际的难度系数
        /// </summary>
        private int m_etraDifficulty;

        /// <summary>
        /// 实际用于生成关卡的方块层
        /// </summary>
        private List<LevelObjLayerData> m_layerList;
        /// <summary>
        /// 实际用于生成关卡的生成器
        /// </summary>
        private LevelDataGenerateHandler m_generateHandler;
        /// <summary>
        /// 储备的奖励块块
        /// </summary>
        private List<int> m_bonusDataList;

        private int m_levelTotalCount = 0;

        /// <summary>
        /// 用于存放回收层的列表
        /// </summary>
        private List<LevelObj> m_recycleLayerObjList;
        private List<LevelObj> m_layerObjList;


        private void Start()
        {
            m_layerList = new List<LevelObjLayerData>();

            m_layerObjList = new List<LevelObj>();
            m_recycleLayerObjList = new List<LevelObj>();

            m_levelStack = new List<int>();
            m_bonusStack = new List<int>();
            m_clearCount = 0;
            m_levelTotalCount = 0;
        }

        /// <summary>
        /// 生成关卡
        /// </summary>
        /// <param name="_standardDifficulty"></param>
        /// <param name="_extraDifficulty"></param>
        /// <param name="_shapeType"></param>
        /// <returns></returns>
        public bool Generate(LevelGenerateData _levelGenerateData)
        { 
            bool result = true;
            m_levelTotalCount = 0;
            m_levelGenerateData = _levelGenerateData;
            m_etraDifficulty = m_levelGenerateData.extraDifficulty;
            m_difficultData = m_levelGenerateData.standardDifficultyData;
            m_extraDifficultData = new LevelConfigData();

            //调整关卡信息
            int extraCubeCount = 0;
            while (extraCubeCount < 3 && m_etraDifficulty > 0)
            {
                extraCubeCount++;

                m_extraDifficultData.totalCount += 0;
                m_extraDifficultData.levelSpriteCount++;

                m_etraDifficulty--;
            }

            //m_extraDifficultData.totalLayer += Mathf.Clamp(m_etraDifficulty / 4, 0, 2);

            try
            {
                switch (_levelGenerateData.shapeType)
                {
                    case ShapeType.Slide:
                    case ShapeType.Circle:
                    case ShapeType.Heart:
                    case ShapeType.Square:
                    default:
                        m_generateHandler = new LevelDataGenerateHandler_Square();
                        m_layerList = m_generateHandler.GenerateLevelData(m_difficultData, m_extraDifficultData, _levelGenerateData);
                        break;
                }

                LevelObj levelObj = null;
                for (int i = 0; i < m_layerList.Count; i++)
                {
                    for (int xIndex = 0; xIndex < m_layerList[i].layerLevelDatas.Length; xIndex++)
                    {
                        for (int yIndex = 0; yIndex < m_layerList[i].layerLevelDatas[xIndex].Length; yIndex++)
                        {
                            levelObj = GetLevelObj();
                            levelObj.InitLevelObj(i, m_layerList[i].layerLevelDatas[xIndex][yIndex].spriteType, OnClickItem);
                            levelObj.transform.localPosition = m_layerList[i].layerLevelDatas[xIndex][yIndex].objPostion * GameDefine.S.Data_CubeSize;

                            //设置遮挡关系
                            //if (i > 0)
                            //{
                                //for (int maskXIndex = 0; maskXIndex < m_layerList[i - 1].layerLevelDatas.Length; maskXIndex++)
                                //{
                                //    for (int maskYIndex = 0; maskYIndex < m_layerList[i - 1].layerLevelDatas[maskXIndex].Length; maskYIndex++)
                                //    {
                                //        if (Mathf.Abs(m_layerList[i - 1].layerLevelDatas[maskXIndex][maskYIndex].objPostion.x - m_layerList[i].layerLevelDatas[xIndex][yIndex].objPostion.x) < 1 &&
                                //            Mathf.Abs(m_layerList[i - 1].layerLevelDatas[maskXIndex][maskYIndex].objPostion.y - m_layerList[i].layerLevelDatas[xIndex][yIndex].objPostion.y) < 1)
                                //        {
                                //            levelObj.SetMaskObj(m_layerList[i - 1].layerLevelDatas[maskXIndex][maskYIndex].levelObj);
                                //        }
                                //    }
                                //}
                            //}

                            if (i > 0)
                            {
                                int x = (int)levelObj.transform.localPosition.x;
                                int y = (int)levelObj.transform.localPosition.y;
                                int layerW = m_layerList[i-1].layerSize.x * GameDefine.S.Data_CubeSize;
                                int layerH = m_layerList[i-1].layerSize.y * GameDefine.S.Data_CubeSize;

                                int w0, w1, h0, h1;

                                if ((x - GameDefine.S.Data_CubeSize / 2 + layerW / 2) % GameDefine.S.Data_CubeSize == 0)
                                {
                                    w0 = w1 = (x - GameDefine.S.Data_CubeSize / 2 + layerW / 2) / GameDefine.S.Data_CubeSize;
                                }
                                else
                                {
                                    w0 = (x - GameDefine.S.Data_CubeSize / 2 + layerW / 2) / GameDefine.S.Data_CubeSize;
                                    w1 = (x - GameDefine.S.Data_CubeSize / 2 + layerW / 2) / GameDefine.S.Data_CubeSize + 1;
                                }

                                if ((y - GameDefine.S.Data_CubeSize / 2 + layerH / 2) % GameDefine.S.Data_CubeSize  == 0)
                                {
                                    h0 = h1 = (y - GameDefine.S.Data_CubeSize / 2 + layerH / 2) / GameDefine.S.Data_CubeSize ;
                                }
                                else
                                {
                                    h0 = (y - GameDefine.S.Data_CubeSize / 2 + layerH / 2) / GameDefine.S.Data_CubeSize ;
                                    h1 = (y - GameDefine.S.Data_CubeSize / 2 + layerH / 2) / GameDefine.S.Data_CubeSize + 1;
                                }

                                Debug.Log(string.Format("i:{0} layerW:{7} layerH:{8}  x:{1} y:{2} w0:{3} w1:{4} h0:{5} h1:{6}", i, x, y, w0, w1, h0, h1, layerW, layerH));

                                levelObj.SetMaskObj(m_layerList[i - 1].layerLevelDatas[w0][h0].levelObj);
                                levelObj.SetMaskObj(m_layerList[i - 1].layerLevelDatas[w0][h1].levelObj);
                                levelObj.SetMaskObj(m_layerList[i - 1].layerLevelDatas[w1][h0].levelObj);
                                levelObj.SetMaskObj(m_layerList[i - 1].layerLevelDatas[w1][h1].levelObj);
                            }

                            levelObj.RefreshState();
                            m_layerList[i].layerLevelDatas[xIndex][yIndex].levelObj = levelObj;
                            m_layerObjList.Add(levelObj);
                            m_levelTotalCount++;
                        }
                    }
                }

                isPlaying = true;
                Debug.Log("TotalCount:" + m_levelTotalCount);
            }
            catch (Exception e)
            {
                result = false;
                Debug.LogWarning("Error Info:" + e.Message);
            }

            m_levelStack.Clear();
            m_clearCount = 0;

            return result;
        } 

        public void LevelDispose()
        {
            m_layerList.Clear();
            m_levelStack.Clear();
            m_bonusStack.Clear();
            m_clearCount = 0;
            m_levelTotalCount = 0;

            while (m_layerObjList.Count > 0)
            {
                LevelObjRecycle(m_layerObjList[0]);
            }

            m_layerObjList.Clear();
            m_generateHandler = null;
        }

        private void LevelObjRecycle(LevelObj levelObj)
        {
            levelObj.transform.SetParent(m_recycleLayerTrans);
            levelObj.transform.localPosition = Vector3.one * 3000f;
            levelObj.RecycleLevelObj();

            m_layerObjList.Remove(levelObj);
            m_recycleLayerObjList.Add(levelObj);
        }

        private LevelObj GetLevelObj()
        {
            if (m_recycleLayerObjList.Count > 0)
            {
                LevelObj levelObj = m_recycleLayerObjList.First();
                m_recycleLayerObjList.RemoveAt(0);
                levelObj.transform.SetParent(this.transform);
                return levelObj;
            }

            return GameObject.Instantiate(GameDefine.S.levelObjPrefabs, transform).GetComponent<LevelObj>();
        }

        #region 关卡内操作

        private bool isPlaying = false;
        private List<int> m_levelStack;
        private int m_clearCount;

        private void Update()
        {
            if (isPlaying)
            {
                if (Input.GetMouseButtonDown(0))
                {
                    //点击后
                    GameObject obj = GetFirstPickGameObject(Input.mousePosition);
                    if (obj != null && obj.GetComponent<LevelObj>() != null) obj.GetComponent<LevelObj>().OnClick();
                }
            }
        }


        public void OnClickItem(LevelObj obj)
        {
            Debug.Log("OnClick objIndex:" + obj.spriteType);

            int index = m_levelStack.LastIndexOf(obj.spriteType);
            if (index == -1) m_levelStack.Add(obj.spriteType);
            else m_levelStack.Insert(index + 1, obj.spriteType);

            //消除判定
            if (index > 0 && m_levelStack[index - 1] == m_levelStack[index])
            {
                DecorationsManager.S.OnMatch(obj.spriteType);
                UIManager.S.RefreshGameUI(m_levelStack, index - 1);

                m_clearCount += 3;
                m_levelStack.RemoveAt(index - 1);
                m_levelStack.RemoveAt(index - 1);
                m_levelStack.RemoveAt(index - 1);
            }
            else
            {
                UIManager.S.RefreshGameUI(m_levelStack);
            }

            string currentListString = "";
            for (int i = 0; i < m_levelStack.Count; i++)
            {
                currentListString += m_levelStack[i];
                currentListString += " ";
            }
            Debug.Log("Current Stack Value String:" + currentListString);

            LevelObjRecycle(obj);
            if (m_levelStack.Count >= GameDefine.S.Data_LevelLimitCount) { isPlaying = false; LevelManager.S.GameFail();  return; }
            if (m_clearCount == m_levelTotalCount ) { isPlaying = false; LevelManager.S.GameWin(); return; }
        }

        /// <summary>
        /// 点击屏幕坐标
        /// </summary>
        /// <param name="position"></param>
        /// <returns></returns>
        public GameObject GetFirstPickGameObject(Vector2 position)
        {
            EventSystem eventSystem = EventSystem.current;
            PointerEventData pointerEventData = new PointerEventData(eventSystem);
            pointerEventData.position = position;
            //射线检测ui
            List<RaycastResult> uiRaycastResultCache = new List<RaycastResult>();
            eventSystem.RaycastAll(pointerEventData, uiRaycastResultCache);
            if (uiRaycastResultCache.Count > 0)
                return uiRaycastResultCache[0].gameObject;
            return null;
        }

        #endregion

        #region 额外奖励包

        /// <summary>
        /// 当局奖励包
        /// </summary>
        private List<int> m_bonusStack;

        /// <summary>
        /// 生成一次奖励包奖励
        /// </summary>
        public void GenerateBonus()
        {
            for (int i = 0; i < GameDefine.S.Data_LevelBonusCount; i++)
            {
                if (m_layerObjList.Count - 1 - i > 0) m_bonusStack.Add(m_layerObjList[m_layerObjList.Count - 1 - i].spriteType);
                else
                {
                    int randomInt= UnityEngine.Random.Range(0, 20);
                    if (randomInt < 2) m_bonusStack.Add(m_bonusDataList[UnityEngine.Random.Range(0, m_bonusDataList.Count)]);
                    else m_bonusStack.Add(m_layerObjList[UnityEngine.Random.Range(0, m_layerList.Count)].spriteType);
                }
            }
        }

        #endregion
    }
}

